package de.zainodis.commons.model.parsing;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Xml;

/**
 * Base class for xml feed parsing.
 * 
 * @author zainodis
 * 
 * @param <T>
 */
public abstract class XmlFeedParser<T> {

   /** List of items being parsed and afterwards returned */
   private Collection<T> items = new ArrayList<T>();

   public void parse(InputStream stream) throws XmlPullParserException, IOException {
	 try {
	    XmlPullParser parser = Xml.newPullParser();
	    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
	    parser.setInput(stream, null);
	    parser.nextTag();
	    processParsedElements(parse(parser));
	 } finally {
	    stream.close();
	 }
   }

   /**
    * This method should be used to directly process parsed items, such as
    * caching them etc.
    * 
    * @param items
    *           the items that have been parsed.
    */
   public abstract void processParsedElements(Collection<T> items);

   public Collection<T> parse(XmlPullParser parser) throws XmlPullParserException, IOException {

	 while (parser.next() != XmlPullParser.END_DOCUMENT) {
	    int eventType = parser.getEventType();

	    if (eventType == XmlPullParser.START_TAG) {
		  String elementName = parser.getName();

		  handleStartTag(elementName, parser);

	    } else if (eventType == XmlPullParser.END_TAG) {
		  handleEndTag(parser.getName(), parser);
	    }
	 }
	 return items;
   }

   public abstract void handleStartTag(String name, XmlPullParser parser)
	    throws XmlPullParserException, IOException;

   public abstract void handleEndTag(String name, XmlPullParser parser)
	    throws XmlPullParserException, IOException;

   protected void addItem(T newItem) {
	 items.add(newItem);
   }

   /**
    * @return the parsing result.
    */
   public abstract Collection<T> getResult();

}
